package foliotracker;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Comparator;
import java.util.UUID;


/**
 * Represents a holding of stock in a company.  The holding may be composed of shares bought on several different
 * occasions.
 */
public class Stock extends Observable implements Serializable
{
	private static final long serialVersionUID = 1L;
	private String symbol, name;
	private double price;
	private List<StockTransaction> transactions;
	private UUID id;
	
	/**
	 * Constructor.  Used when adding a stock to a portfolio for the first time.
	 * @param symbol The stock symbol, e.g. MSFT.
	 * @param name The stock name, e.g. Microsoft.
	 * @param price The current price of the stock, in USD.
	 */
	public Stock(String symbol, String name, double price)
	{
		id = UUID.randomUUID();
		this.symbol = symbol;
		this.name = name;
		this.price = price;
		transactions = new ArrayList<StockTransaction>();
	}
	
	public UUID getId() {
		return id;
	}


	/**
	 * Gets the symbol for the stock.
	 * @return
	 */
	public String getSymbol()
	{
		return symbol;
	}
	
	/**
	 * Gets the name for the stock.
	 * @return
	 */
	public String getName()
	{
		return name;
	}
	
	/**
	 * Gets the last fetched price for the stock.
	 * @return
	 */
	public double getPrice()
	{
		return price;
	}
	
	/**
	 * Sets the price of the stock and notifies observers of the change.
	 * @param value
	 */
	public void setPrice(double value)
	{
		price = value;
		super.setChanged();
		super.notifyObservers();
	}
	
	/**
	 * Gets the number of shares held.
	 * @return
	 */
	public int getQuantity()
	{
		int quantity = 0;
		for(StockTransaction trans : transactions){
			quantity += trans.getQuantity();
		}
		return quantity;
	}
	
	/**
	 * Gets the cost of the stock.
	 * @return
	 */
	public double getInitialCost()
	{
		//loop through the transactions and sum the costs * quantities
		double cost = 0;
		for(StockTransaction tran : transactions){
			cost += (tran.getPrice() * tran.getQuantity());
		}
		return cost;
	}
	
	/**
	 * Gets the value of the stock.
	 * @return
	 */
	public double getTotalValue()
	{
		//price * quantity
		return this.getPrice() * this.getQuantity();
	}
	
	/**
	 * Gets the profit or loss made on the stock based on the current value.
	 * @return
	 */
	public double getProfit()
	{
		//getValue() - getCost()
		return this.getTotalValue() - this.getInitialCost();
	}
	
	
	
	public double getPercentageGain()
	{
		double cost = this.getInitialCost();
		
		if (cost == 0)
		{
			return 0;
		}
		else
		{
			return (this.getTotalValue() - cost) / cost;
		}
	}
	
	/**
	 * Gets the transactions for this stock.
	 * @return
	 */
	public List<StockTransaction> getTransactions()
	{
		return transactions;
	}
	
	/**
	 * Increases the quantity of stock held by adding an item to the transactions and notifies observers of the change.
	 * 
	 * @param date The date the transaction was made on.
	 * @param quantity The quantity bought.
	 * @param price The price the stock was bought for.
	 */
	public void buy(Date date, int quantity, double price)
	{
		//make a new StockTransaction instance and add it to the list
		StockTransaction trans = new StockTransaction(date, quantity, price);
		transactions.add(trans);
		
		super.setChanged();
		super.notifyObservers();
	}
	
	/**
	 * Decreases the amount of stock held on a first-in-first-out basis and notifies observers of the change.
	 * 
	 * @param quantity The amount of stock to sell.
	 * @exception IllegalArgumentException quantity is larger than the total quantity held.
	 */
	public void sell(int quantity)
	{
		if(this.getQuantity() < quantity)
			throw new IllegalArgumentException("Quantity being sold is larger than total quantity of current shares");
		
		//start with the least recent transaction
		Collections.sort(transactions, new StockComparator());
		
		while(quantity > 0)
		{
			StockTransaction trans = transactions.get(0);
			
			if(trans.getQuantity() <= quantity)
			{
				quantity -= trans.getQuantity();
				transactions.remove(0);
			}
			else
			{
				trans.setQuantity(trans.getQuantity()-quantity);
				break;
			}
		}
		
		super.setChanged();
		super.notifyObservers();
	}
	
	class StockComparator implements Comparator<StockTransaction>
	{
		@Override
		public int compare(StockTransaction arg0, StockTransaction arg1) {
			return arg0.getDate().compareTo(arg1.getDate());
		}
		
	}
}
